package com.atguigu.dga230301.governance.service.impl;

import com.atguigu.dga230301.ds.bean.TDsTaskDefinition;
import com.atguigu.dga230301.ds.bean.TDsTaskInstance;
import com.atguigu.dga230301.ds.service.TDsTaskDefinitionService;
import com.atguigu.dga230301.ds.service.TDsTaskInstanceService;
import com.atguigu.dga230301.governance.assess.Assessor;
import com.atguigu.dga230301.governance.assess.spec.TecOwnerAssess;
import com.atguigu.dga230301.governance.bean.AssessParam;
import com.atguigu.dga230301.governance.bean.GovernanceAssessDetail;
import com.atguigu.dga230301.governance.bean.GovernanceMetric;
import com.atguigu.dga230301.governance.mapper.GovernanceAssessDetailMapper;
import com.atguigu.dga230301.governance.service.*;
import com.atguigu.dga230301.governance.util.SpringBeanProvider;
import com.atguigu.dga230301.meta.bean.TableMetaInfo;
import com.atguigu.dga230301.meta.bean.TableMetaInfoExtra;
import com.atguigu.dga230301.meta.service.TableMetaInfoExtraService;
import com.atguigu.dga230301.meta.service.TableMetaInfoService;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.PrintWriter;
import java.io.StringWriter;
import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.function.Supplier;
import java.util.stream.Collectors;

/**
 * <p>
 * 治理考评结果明细 服务实现类
 * </p>
 *
 * @author zhangjunyi
 * @since 2023-07-03
 */
@Service
@DS("dga")
public class GovernanceAssessDetailServiceImpl extends ServiceImpl<GovernanceAssessDetailMapper, GovernanceAssessDetail> implements GovernanceAssessDetailService {
    ThreadPoolExecutor threadPoolExecutor=new ThreadPoolExecutor(100,100,60, TimeUnit.SECONDS,new LinkedBlockingDeque<>());
    @Autowired
    TableMetaInfoService tableMetaInfoService;
    @Autowired
    TableMetaInfoExtraService tableMetaInfoExtraService;
    @Autowired
    GovernanceMetricService governanceMetricService;

    @Autowired
    TDsTaskInstanceService tDsTaskInstanceService;

    @Autowired
    TDsTaskDefinitionService tDsTaskDefinitionService;

    @Autowired
    GovernanceAssessTableService governanceAssessTableService;

    @Autowired
    GovernanceAssessTecOwnerService governanceAssessTecOwnerService;

    @Autowired
    GovernanceAssessGlobalService governanceAssessGlobalService;

    @Override
    public void assessAllTableMetrics(String assessDate) {
        //0.重复考评的时候删除之前已经考评的结果
        remove(new QueryWrapper<GovernanceAssessDetail>().eq("assess_date", assessDate));

        //1.获取表所有的元数据（元数据，辅助信息表）

/*       这么做从逻辑上来说是可以实现的，但是要考虑到数据库IO，这相当于要查询 tableMetaInfoList.size()次数据库，可能会对数据库的压力过大
List<TableMetaInfo> tableMetaInfoList = tableMetaInfoService.list(new QueryWrapper<TableMetaInfo>().eq("assess_date", "select (max(assess_date) from table_meta_info)"));
        for (TableMetaInfo tableMetaInfo : tableMetaInfoList) {
            TableMetaInfoExtra tableMetaInfoExtra = tableMetaInfoExtraService.getOne(new QueryWrapper<TableMetaInfoExtra>().eq("table_name", tableMetaInfo.getTableName()).eq("schema_name", tableMetaInfo.getSchemaName()));
            tableMetaInfo.setTableMetaInfoExtra(tableMetaInfoExtra);
        }*/

        //可以通过sql的方式将两种表join起来 以此减少数据库的IO
        List<TableMetaInfo> tableMetaInfoList = tableMetaInfoService.getAllTableMetaInfo();

        //创建Map集合用来存放所有的表的元数据 k：库名+表名  v：TableMetaInfo
        HashMap<String, TableMetaInfo> fullTableNameToMetaInfo = new HashMap<>();
        for (TableMetaInfo tableMetaInfo : tableMetaInfoList) {
            fullTableNameToMetaInfo.put(tableMetaInfo.getSchemaName() + "." + tableMetaInfo.getTableName(), tableMetaInfo);
        }

        //获取所有要考评的表名
        List<String> allTableName = tableMetaInfoList.stream().map(tableMetaInfo -> tableMetaInfo.getSchemaName() + "." + tableMetaInfo.getTableName()).collect(Collectors.toList());

        //获取表的任务定义
        Map<String, TDsTaskDefinition> dsTaskDefinitionMap = tDsTaskDefinitionService.getTDsTaskDefinitionByDt(assessDate, allTableName);

        //获取到DS中考评日期运行的实例
        List<TDsTaskInstance> tdsTaskInstanceByAssessDate = tDsTaskInstanceService.getTdsTaskInstanceByAssessDate(assessDate);

        //2.获取所有的已启用的考评指标（governance_metric）
        List<GovernanceMetric> governanceMetricList = governanceMetricService.list(new QueryWrapper<GovernanceMetric>().eq("is_disabled", "0"));

        //创建集合用来收集期货
        ArrayList<CompletableFuture<GovernanceAssessDetail>> completableFutureArrayList = new ArrayList<>();

        //3.遍历获取所有的元数据拿到每一张表的元数据（为了对这个表做考评）
        //创建list集合用来保存考评明细
        ArrayList<GovernanceAssessDetail> governanceAssessDetails = new ArrayList<>(tableMetaInfoList.size() * governanceMetricList.size());
        for (TableMetaInfo tableMetaInfo : tableMetaInfoList) {
            for (GovernanceMetric governanceMetric : governanceMetricList) {
                Assessor assessor = SpringBeanProvider.getBean(governanceMetric.getMetricCode(), Assessor.class);


                //创建考评参数对象
                AssessParam assessParam = new AssessParam();
                assessParam.setAssessDate(assessDate);
                assessParam.setTableMetaInfo(tableMetaInfo);
                assessParam.setGovernanceMetric(governanceMetric);
                assessParam.setFullTableNameToMetaInfo(fullTableNameToMetaInfo);
                assessParam.setTDsTaskInstanceList(tdsTaskInstanceByAssessDate);
                assessParam.setTDsTaskDefinition(dsTaskDefinitionMap.get(tableMetaInfo.getSchemaName()+"."+tableMetaInfo.getTableName()));
                //针对每个指标做考评
                CompletableFuture<GovernanceAssessDetail> assessDetailCompletableFuture = CompletableFuture.supplyAsync(new Supplier<GovernanceAssessDetail>() {
                    @Override
                    public GovernanceAssessDetail get() {
                        return assessor.mainAssess(assessParam);
                    }
                },threadPoolExecutor);
                completableFutureArrayList.add(assessDetailCompletableFuture);
//                GovernanceAssessDetail governanceAssessDetail = assessor.mainAssess(assessParam);
//                governanceAssessDetails.add(governanceAssessDetail);

/*  如果按照这种写法的话每增加一个指标需要补充elseif这个方法 不符合代码的开闭原则，也就意味着没次都需要修改代码
                GovernanceAssessDetail governanceAssessDetail = new GovernanceAssessDetail();
                governanceAssessDetail.setAssessDate(assessDate);
                governanceAssessDetail.setTableName(tableMetaInfo.getTableName());
                governanceAssessDetail.setSchemaName(tableMetaInfo.getSchemaName());
                governanceAssessDetail.setMetricId(governanceMetric.getId()+"");
                governanceAssessDetail.setMetricName(governanceMetric.getMetricName());
                governanceAssessDetail.setGovernanceType(governanceMetric.getGovernanceType());
                governanceAssessDetail.setTecOwner(tableMetaInfo.getTableMetaInfoExtra().getTecOwnerUserName());
                //默认满分十分
                governanceAssessDetail.setAssessScore(BigDecimal.TEN);

                try{
                    if (governanceMetric.getMetricCode().equals("TEC_OWNER")){
                        //求是否有技术负责人
                        if (tableMetaInfo.getTableMetaInfoExtra().getTecOwnerUserName()==null||tableMetaInfo.getTableMetaInfoExtra().getTecOwnerUserName().length()<0){
                            governanceAssessDetail.setAssessScore(BigDecimal.ZERO);
                            governanceAssessDetail.setAssessProblem("没有技术负责人");
                            String governanceUrl = governanceMetric.getGovernanceUrl();
                            String url = governanceUrl + tableMetaInfo.getTableMetaInfoExtra().getId();
                            governanceAssessDetail.setGovernanceUrl(url);
                        }
                    }
                 *//*   else if (governanceMetric.getMetricCode().equals("BUSI_OWNER")) {

                    } else if (governanceMetric.getMetricCode().equals( "TABLE_NAME_STANDARD")) {

                    }*//*
                }catch (Exception e){
                    //有异常
                    governanceAssessDetail.setIsAssessException("1");
                    StringWriter stringWriter = new StringWriter();
                    PrintWriter printWriter = new PrintWriter(stringWriter);
                    e.printStackTrace(printWriter);

                    //将异常信息写入表中
                    governanceAssessDetail.setAssessExceptionMsg(stringWriter.toString().substring(0,Math.min(stringWriter.toString().length(),2000)));
                }

                governanceAssessDetail.setCreateTime(new Date());*/


            }
        }

        List<GovernanceAssessDetail> governanceAssessDetailList = completableFutureArrayList.stream().map(governanceAssessDetailCompletableFuture -> governanceAssessDetailCompletableFuture.join()).collect(Collectors.toList());
//        saveOrUpdateBatch(governanceAssessDetails);
        saveOrUpdateBatch(governanceAssessDetailList);
        //4.再遍历所有已启用的考评指标，针对每张表做考评
        //5.将考评明细写到governance_assess_detail这个表中
    }

    @Override
    public void mainAssess(String assessDate) {
        long startTime = System.currentTimeMillis();
        //每个指标项的考评
        assessAllTableMetrics(assessDate);
        long endTime = System.currentTimeMillis();
        System.out.println("运行时间："+(endTime-startTime));

        //分数汇总
        governanceAssessTableService.calcGovernanceAssessTable(assessDate);

        governanceAssessTecOwnerService.calcAssessByTecOwner(assessDate);

        governanceAssessGlobalService.calcGlobalScore(assessDate);

    }
}
